package benchmarks.tpch.mongo.queries;

import api.Configuration;
import api.connection.ConnectionMongo;
import api.connection.DBConnection;
import api.result.Result;
import com.mongodb.*;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import org.bson.BsonDocument;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.regex.Pattern;

public class Q21Mongo extends GenericQueryMongo {
    public static final String queryName = "Q21";

    public Q21Mongo(){
        super.queryName = queryName;
    }

    private static String matchStringQuery = "{" +
            "$match: {$and : [" +
            "{\"order.orderstatus\" : \"F\"}," +
            "{\"partsupp.supplier.nation.name\" : { $regex : '^SAUDI ARABIA'} }" +
            "]}}";

    private static String addFieldStringQuery = "{" +
            "$addFields: {" +
            "\"gt\": {$gt : [\"$receiptdate\", \"$commitdate\"]}" +
            "}}";

    private static String projectStringQuery = "{$project: {" +
            "\"orderkey\" : \"$order.orderkey\"," +
            "\"suppkey\" : \"$partsupp.supplier.suppkey\"," +
            "\"s_name\" : \"$partsupp.supplier.name\"" +
            "}}";

    private boolean isLegal(MongoDatabase database, Document doc) {
        int orderkey = doc.getInteger("orderkey");
        int suppkey = doc.getInteger("suppkey");
        String query = "{ $match : {$and : [ " +
                "{\"order.orderkey\" : " +
                orderkey +
                "}," +
                "{\"partsupp.supplier.suppkey\" : {$ne : " +
                suppkey +
                "}} " +
                "]}}";
        ArrayList<BsonDocument> aggregateList = new ArrayList<>();
        aggregateList.add(BsonDocument.parse(query));
        aggregateList.add(BsonDocument.parse(addFieldStringQuery));
        aggregateList.add(BsonDocument.parse("{$sortByCount : \"$gt\"}"));
        AggregateIterable<Document> result = database.getCollection("deals").aggregate(aggregateList);
        MongoCursor<Document> iterator = result.iterator();
        ArrayList<Document> results = new ArrayList<>();
        while (iterator.hasNext()) {
            results.add(iterator.next());
        }
        return (results.size() == 1 && !results.get(0).getBoolean("_id"));
    }

    public Result run(DBConnection dbConnection) {
        ConnectionMongo connectionMongo = (ConnectionMongo)dbConnection;
        MongoClient mongoClient = connectionMongo.makeConnection();
        MongoDatabase database = mongoClient.getDatabase("tpch");
        ArrayList<BsonDocument> aggregateQuery = new ArrayList<>();
        aggregateQuery.add(BsonDocument.parse(matchStringQuery));
        aggregateQuery.add(BsonDocument.parse(addFieldStringQuery));
        aggregateQuery.add(BsonDocument.parse("{$match : {\"gt\" : true} }"));
        aggregateQuery.add(BsonDocument.parse(projectStringQuery));
        AggregateIterable<Document> result  = database.getCollection("deals").aggregate(aggregateQuery);
        MongoCursor<Document> iterator = result.iterator();
        ArrayList<Document> results = new ArrayList<>();
        while (iterator.hasNext()) {
            Document doc = iterator.next();
            if (isLegal(database, doc)) {
                results.add(doc);
            }
        }
        //didn't count
        return null;
    }

//    public Result run(DBConnection dbConnection){
//        MongoClient mongoClient = (MongoClient)dbConnection.makeConnection();
//        String databaseName = "tpch";
//        String collectionName = "deals";
//
//        String nationName = "SAUDI ARABIA";
//        DB db = mongoClient.getDB(databaseName);
//        DBCollection collection = db.getCollection(collectionName);
//
//        BasicDBObject query = new BasicDBObject();
//        Pattern nation = Pattern.compile("^" + nationName);
//        query.append("order.orderstatus", "F")
//                .append("partsupp.supplier.nation.name", new BasicDBObject("$regex", nation));
//
//        BasicDBObject query2 = new BasicDBObject();
//        query2.append("$where", "this.receiptdate > this.commitdate");
//
//        String where1 = "function(){"
//                + "return db.deals.findOne({$and : ["
//                + "{\"order.orderkey\" : this.order.orderkey},"
//                + "{\"partsupp.supplier.suppkey\" : {\"ne\" : this.partsupp.supplier.suppkey}},"
//                +"]}) != null;"
//                +"}";
//
//        query2.append("$where", where1);
//
//        String where2 = "function(){"
//                + "return db.deals.findOne({$and : ["
//                + "{\"order.orderkey\" : this.order.orderkey},"
//                + "{\"partsupp.supplier.suppkey\" : {\"ne\" : this.partsupp.supplier.suppkey}},"
//                + "{$where : \"this.receiptdate > this.commitdate\"}"
//                +"]}) == null;"
//                +"}";
//        query2.append("$where", where2);
//
//        DBCollection tmp = db.getCollection("tmp");
//        tmp.drop();
//
//        DBCursor cursor = collection.find(query);
//        while(cursor.hasNext()){
//            DBObject obj = cursor.next();
//            tmp.insert(obj);
//            //System.out.println(obj.toString());
//        }
//
//        BasicDBObject project = new BasicDBObject();
//        project.append("_id", 0)
//                .append("s_name", "$partsupp.supplier.name");
//
//        BasicDBObject group = new BasicDBObject();
//        group.append("_id", "$s_name")
//                .append("numwait", new BasicDBObject("$sum", 1));
//
//        BasicDBObject sort = new BasicDBObject();
//        sort.append("numwait", -1)
//                .append("_id", 1);
//
//        AggregationOutput output = tmp.aggregate(new BasicDBObject("$match", query), /*multisupp, onlyfail,*/
//                new BasicDBObject("$project", project), new BasicDBObject("$group", group), new BasicDBObject("$sort", sort));
//        /*Iterable<DBObject> list = output.results();
//        for(DBObject dbObject:list){
//            System.out.println(dbObject.toString());
//        }*/
//
//        return null;
//    }

    private static class TestQ21{
        public static void main(String[] args){
            Configuration config = new Configuration();
            config.setBenchmark("tpch");
            config.setDb_username("root");
            config.setDb_password("123456");
            Q21Mongo q21Mongo = new Q21Mongo();
            DBConnection dbConnection =new ConnectionMongo(config);
            q21Mongo.run(dbConnection);
        }
    }
}
